using System.Collections;
using System.Collections.Generic;

namespace System.Linq.Expressions
{
    public class LambdaExpressionRebuilder : ExpressionVisitorEx, IEnumerable
    {
        public class Rule
        {
            public Func<Expression, bool> Selector { get; set; }
            public Expression NewNode { get; set; }

            public Rule(Func<Expression, bool> Selector, Expression NewNode)
            {
                this.Selector = Selector;
                this.NewNode = NewNode;
            }
        }

        public class Rule<T> : Rule where T : Expression
        {
            public Rule(Func<T, bool> Selector, Expression Node) : base(s => s is T && Selector((T)s), Node) { }
        }

        private readonly List<Rule> f_NewValues;

        public LambdaExpressionRebuilder(params Rule[] NewValues) : this((IEnumerable<Rule>)NewValues) { }
        public LambdaExpressionRebuilder(IEnumerable<Rule> NewValues) { f_NewValues = NewValues.ToList(); }

        public override Expression Visit(Expression node)
        {
            var V = f_NewValues.First(v => v.Selector(node));
            return V == null ? base.Visit(node) : V.NewNode;
        }

        public void Add(Func<Expression, bool> Selector, Expression NewNode)
        {
            f_NewValues.Add(new Rule(Selector, NewNode));
        }

        public IEnumerator GetEnumerator() { return f_NewValues.GetEnumerator(); }
    }
}